package aspectLog;

import StaticFinal.CrudType;
import base.IBaseEntity;
import base.IBaseMapper;
import org.apache.shiro.SecurityUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import services.log.TableEditLogServices;
import servicesImp.log.InsertTableEditLogListThread;
import util.JsonUtil;
import wt.entity.log.TableEditLogWithBLOBs;
import wt.entity.upms.Account;
import wt.staticData.TableName;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Set;


@Component
@Aspect
public class PrintSystemLogAspect {
    private static Logger log = LoggerFactory.getLogger(PrintSystemLogAspect.class);

    @Autowired
    TableEditLogServices tableEditLogServices;

    public  static final Set<String> excludeTable=new HashSet<String>();//不进行日志记录的表名
    static {
        excludeTable.add(TableName.LOG_TABLE_EDIT);
        excludeTable.add(TableName.EMS_LEADER_CHECK);
        excludeTable.add(TableName.LOG_LOGIN);
    }


    /**
     * 删除操作日志记录
     * @param joinPoint
     * @return
     * @throws Exception
     * @throws Throwable
     */
    @Around("@annotation(aspect.DeleteOperationLog)")
    public Object deleteOperationLog(JoinPoint joinPoint) throws  Throwable {

        if (excludeTable.contains(getTableName(joinPoint))){
             return    ((ProceedingJoinPoint) joinPoint).proceed();//执行该方法
        }



        TableEditLogWithBLOBs tableEditLog = getTableEditLog(joinPoint);
        tableEditLog.setTableOperation(CrudType.delete);
        String methodName = getMethodName(joinPoint);
        if (methodName.equals("deleteByExample")) {
            List<Object> deleteList = getMapper(joinPoint).selectByExample(getMethodParams(joinPoint)[0]);

            Object object = ((ProceedingJoinPoint) joinPoint).proceed();//执行该方法

            new InsertTableEditLogListThread(deleteList,tableEditLogServices,tableEditLog).start();

            return object;
        } else {
            Object deleteObj = getMapper(joinPoint).selectByPrimaryKey((String) getMethodParams(joinPoint)[0]);

            Object object = ((ProceedingJoinPoint) joinPoint).proceed();//执行该方法

            tableEditLog.setTableData(JsonUtil.obj2Json(deleteObj));

            tableEditLogServices.insertSelective(tableEditLog);

            return object;
        }
    }


    /**
     * 更新操作日志记录
     * @param joinPoint
     * @throws Exception
     */

    @AfterReturning("@annotation(aspect.UpdateOperationLog)")
    public void updateOperationLog(JoinPoint joinPoint) throws Exception {

        if (excludeTable.contains(getTableName(joinPoint))){
            return;
        }

        String methodName = getMethodName(joinPoint);
        TableEditLogWithBLOBs tableEditLog = getTableEditLog(joinPoint);
        tableEditLog.setTableOperation(CrudType.update);
        if (methodName.startsWith("updateByExample")) {

            List<Object> objectList = getMapper(joinPoint).selectByExample(getMethodParams(joinPoint)[1]);
            new InsertTableEditLogListThread(objectList,tableEditLogServices,tableEditLog).start();


        } else {

            Object object = getMapper(joinPoint).selectByPrimaryKey(((IBaseEntity) getMethodParams(joinPoint)[0]).getId());
            tableEditLog.setTableData(JsonUtil.obj2Json(object));
            tableEditLogServices.insertSelective(tableEditLog);
        }


    }

    /**
     * 添加操作日志记录
     * @param joinPoint
     * @throws Exception
     */
    @AfterReturning("@annotation(aspect.InsertOperationLog)")
    public void insertOperationLog(JoinPoint joinPoint) throws Exception {
        if (excludeTable.contains(getTableName(joinPoint))){
            return;
        }
        TableEditLogWithBLOBs tableEditLog = getTableEditLog(joinPoint);
        tableEditLog.setTableOperation(CrudType.insert);
        Object object = getMapper(joinPoint).selectByPrimaryKey(((IBaseEntity) getMethodParams(joinPoint)[0]).getId());
        tableEditLog.setTableData(JsonUtil.obj2Json(object));
        tableEditLogServices.insertSelective(tableEditLog);
    }


    /**
     * 获取表名
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private String getTableName(JoinPoint joinPoint) throws Exception {
        Class targetClass = joinPoint.getTarget().getClass();
        Method m = targetClass.getDeclaredMethod("getTableName");
        String tableName = (String) m.invoke(joinPoint.getTarget());
        return tableName;
    }

    /**
     * 获取Mapper
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private IBaseMapper getMapper(JoinPoint joinPoint) throws Exception {
        Class targetClass = joinPoint.getTarget().getClass();
        Method m = targetClass.getDeclaredMethod("getMapper");
        IBaseMapper mapper = (IBaseMapper) m.invoke(joinPoint.getTarget());
        return mapper;
    }


    /**
     * 获取请求参数
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private Object[] getMethodParams(JoinPoint joinPoint) throws Exception {
        Object[] arguments = joinPoint.getArgs();
        return arguments;
    }

    /**
     * 获取请求方法
     * @param joinPoint
     * @return
     * @throws Exception
     */
    private String getMethodName(JoinPoint joinPoint) throws Exception {
        return joinPoint.getSignature().getName();
    }



    TableEditLogWithBLOBs getTableEditLog(JoinPoint joinPoint) throws Exception {
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        String uri = request.getRequestURI();
        String ip = request.getRemoteAddr();
        String httpMethod = request.getMethod();
        String httpParam = JsonUtil.obj2Json(request.getParameterMap());
        TableEditLogWithBLOBs tableEditLog = new TableEditLogWithBLOBs();
        tableEditLog.setUri(uri);
        tableEditLog.setIp(ip);
        tableEditLog.setHttpMethod(httpMethod);
        tableEditLog.setHttpParam(httpParam);
        tableEditLog.setRequestTime(new Date());
        tableEditLog.setTableName(getTableName(joinPoint));
        if (SecurityUtils.getSubject().getPrincipal()!=null){
            tableEditLog.setAccountId(((Account) SecurityUtils.getSubject().getPrincipal()).getLoginName());
        }else{
            Object userLoginName=request.getSession().getAttribute("_userLoginName");
            if (userLoginName==null){
                throw new RuntimeException("请在session中添加 key为”_userLoginName“ value为具体使用者的标识(String类型)");
            }
            tableEditLog.setAccountId((String) userLoginName);
        }

        return tableEditLog;
    }

}